home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / MONITOR / TXTCAP20.ARJ / TEXTCAP.ASM < prev    next >
Assembly Source File  |  1991-12-05  |  41KB  |  864 lines

  1. ;----------------------------------------------------------------------
  2. ; TEXTCAP is a resident utility which copies a text screen
  3. ; to a file. Activate TEXTCAP by pressing Ctrl-F9 or the hot key
  4. ; specified by /K<number> on the command line. Help by /?.
  5. ; The filename will be SCNxxxxx.TXT. The number part begins with 00000
  6. ; and is incremented by 1 each time TEXTCAP is activated.
  7. ; ---> Authored originally by Tom Kihlken for PC Magazine in 1987   <---
  8. ; ---> Heavily modified by TapirSoft Gisbert W.Selke, 04 Dec 1991   <---
  9. ; amongst others a mini-API via INT 16h, ax=4252h..4254h:
  10. ; 4252h : installation check, responds with 5242h
  11. ; 4253h : removal from memory, responds with segment we used; calling programme
  12. ;         must de-allocate this segment!
  13. ; 4254h : dump text screen now, responds with 5442h
  14. ;-----------------------------------------------------------------------
  15.  
  16. ;-----------------------------------------------------------------------
  17. BIOS_SEG        SEGMENT AT 0040H
  18.  
  19.                 ORG     0017H
  20. KB_FLAG         DB      ?               ;BIOS keyboard shift status
  21.  
  22. BIOS_SEG        ENDS
  23.  
  24. ;=======================================================================
  25. CSEG            SEGMENT
  26.                 Assume  CS:CSEG, DS:CSEG, ES:CSEG
  27.  
  28.                 Org     0080h
  29. CmdLine         Label   Byte                    ; pointer to command line
  30.  
  31.                 ORG     0100H                   ; Beginning for .COM programs
  32. START:          JMP     INITIALIZE              ; Initialization code is at end
  33.  
  34. ;-----------------------------------------------------------------------
  35. ; Data needed by this program
  36. ;-----------------------------------------------------------------------
  37.  
  38. NROWS           Equ     50                      ; max number of lines on screen
  39. NCOLS           Equ     132                     ; max number of columns per line
  40. NBYTES          Equ     NROWS*NCOLS*2           ; length of screen in bytes
  41.  
  42. DosCall         Equ     21h                     ; DOS interrupt number
  43. PrintChar       Equ     02h                     ; DOS function 'print char'
  44. PrintString     Equ     09h                     ; DOS function 'print string'
  45. SetVec          Equ     2500h                   ; DOS function 'set interrupt vector'
  46. Keep            Equ     3100h                   ; DOS function 'stay resident'
  47. GetVec          Equ     3500h                   ; DOS function 'get interrupt vector'
  48. FreeMem         Equ     49h                     ; DOS function 'free memory'
  49. Exec            Equ     4Bh                     ; DOS function 'exec'
  50. ExitCode        Equ     4Ch                     ; exit with error code
  51.  
  52. ChkCode         Equ     4252h                   ; our special installation check
  53. RemoveCode      Equ     4253h                   ; our special request for removal
  54. DumpCode        Equ     4254h                   ; our special request for dumps
  55. InstalledCode   Equ     5242h                   ; footprint 'installed'
  56.  
  57. Tab             Equ     09h                     ; ASCII tab
  58. CR              Equ     0Dh                     ; carriage return
  59. LF              Equ     0Ah                     ; line feed
  60. CtrlZ           Equ     1Ah                     ; end-of-file mark
  61.  
  62. CopyRight       db      CR, 'TEXTCAP 2.0 (c) 1987/91 Ziff Communications Co'
  63.                 db      '/TapirSoft Gisbert W.Selke$', CtrlZ
  64. FileName        db      80 Dup (0)              ; output path and file name
  65. FileNamePtr     dw      FileName                ; pointer to beginning etc.
  66.  
  67. HotKey          db      43h             ; scan code of F9
  68. ShiftMask       db      00000100b       ; shift mask: any Ctrl key
  69. OldInt09        DD      ?       ;Old hardware keyboard interrupt vector
  70. OldInt13        DD      ?       ;Old BIOS disk I/O interrupt vector
  71. OldInt16        DD      ?       ;Old keyboard input interrupt vector
  72. OldInt21        DD      ?       ;Old DOS function interrupt vector
  73. CRT_MODE        DB      ?       ;Current video mode
  74. CRT_ROWS        DB      ?       ;Number of lines on screen
  75. CRT_COLS        DB      ?       ;Number of columns on screen, possibly adjusted
  76. CRT_SIZE        DW      ?       ;Actual screen size in bytes (chars+attributes)
  77. ACTIVE_PAGE     DB      ?       ;Number of active video page
  78. WriteFile       DB      0       ;If=1, need to write to disk
  79. ACTIVE          DB      0       ;Indicates CAPTURE is in use
  80. DOS_Stat        DB      0       ;Current DOS function indicator
  81. Busy_flags      DB      0       ;Bit masked as follows:
  82.                                 ;  1 - DOS function is active
  83.                                 ;  2 - BIOS disk I/O is active
  84.  
  85. ;-----------------------------------------------------------------------
  86. ; CAPTURE reads the screen and stores it in an internal buffer.
  87. ;-----------------------------------------------------------------------
  88.  
  89. CAPTURE         PROC    NEAR
  90.                 Assume  DS:CSEG, ES:BIOS_SEG
  91.  
  92.                 MOV     AH, 0Fh                 ;Get current video mode
  93.                 INT     10h
  94.                 MOV     CRT_COLS, AH            ;Store number of screen columns
  95.                 MOV     CRT_MODE, AL            ;Store video mode
  96.                 MOV     ACTIVE_PAGE, BH         ;Store video page
  97.  
  98.                 XCHG    AH, AL                  ;Number of columns in AL
  99.                 XOR     AH, AH
  100.                 CMP     AX, NCOLS               ;Compare to maximum; may be > 127!
  101.                 JBE     SAVE_COLS               ;Skip if we can handle it
  102.                 MOV     AL, NCOLS               ;Else use adjusted number
  103. SAVE_COLS:      MOV     CRT_COLS, AL            ;Store in CRT_COLS
  104.                 PUSH    AX                      ;Save for a sec
  105.  
  106.                 MOV     DL, 25d                 ;Default number of lines
  107.                 MOV     AL, CRT_MODE            ;Get video mode
  108.                 CMP     AL, 07h                 ;If 80*25 text, then ok
  109.                 JE      SET_SIZE
  110.                 MOV     AX, 1130h               ;Else try to get max line
  111.                 INT     10h                     ; ... in DL
  112.                 INC     DL                      ;Adjust to get # lines
  113.                 CMP     DL, NROWS               ;at most NROWS allowed!
  114.                 JBE     SET_SIZE
  115.                 MOV     DL, NROWS
  116. SET_SIZE:
  117.                 MOV     CRT_ROWS, DL            ;Jot down # lines
  118.                 POP     AX                      ;Get back number of columns
  119.                 MUL     DL                      ;Multiply to get #chars on screen
  120.                 SHL     AX, 1                   ;Double for chars+attributes
  121.                 MOV     CRT_SIZE, AX            ;This many bytes to write!
  122.  
  123.                 MOV     AH, 03h                 ;Cursor pos for this page
  124.                 MOV     BH, ACTIVE_PAGE
  125.                 INT     10h
  126.                 PUSH    DX                      ;Save the cursor location
  127.                 MOV     DI,OFFSET BUFFER        ;DS:DI points to the buffer
  128.                 XOR     DX,DX                   ;Start at row 0, column 0
  129. READ_LOOP:
  130.                 MOV     AH, 02h
  131.                 MOV     BH, ACTIVE_PAGE
  132.                 INT     10h             ;Tell BIOS where the cursor is
  133.                 MOV     BH,ACTIVE_PAGE  ;Get active page from BIOS data
  134.                 MOV     AH,8            ;BIOS function to read character
  135.                 INT     10H             ;Read the character/attribute
  136.  
  137.                 MOV     [DI],AX         ;Put the character in buffer
  138.                 INC     DI              ;Increment the pointer twice
  139.                 INC     DI              ;Since we stored a word
  140.  
  141.                 INC     DL              ;Do the next char in same row
  142.                 CMP     DL,DS:CRT_COLS  ;At the right border yet?
  143.                 JNE     READ_LOOP       ;Do all characters in this row
  144.                 INC     DH              ;Move to next row
  145.                 XOR     DL,DL           ;Back to left edge (Column 0)
  146.                 CMP     DH,DS:CRT_ROWS  ;Done all rows yet?
  147.                 JNE     READ_LOOP       ;Loop until whole screen is read
  148.                 MOV     AH, 02h         ;Cursor pos for this page
  149.                 MOV     BH, ACTIVE_PAGE
  150.                 POP     DX
  151.                 INT     10h             ;Recover the cursor position
  152.                 RET                     ;Then were finished
  153. CAPTURE         ENDP
  154.  
  155. ;-----------------------------------------------------------------------
  156. ; This copies the buffer contents to a file.  It should only be called
  157. ; when DOS is in a stable and reentrant condition.
  158. ;-----------------------------------------------------------------------
  159. WRITE_TO_FILE   PROC    NEAR
  160.                 Assume  DS:NOTHING, ES:NOTHING
  161.  
  162.                 MOV     WriteFile,0     ;Turn off request flag
  163.                 STI                     ;Get interrupts back on
  164.                 PUSH    AX              ;Must preserve all registers
  165.                 PUSH    BX
  166.                 PUSH    CX
  167.                 PUSH    DX
  168.                 PUSH    BP
  169.                 PUSH    DS
  170.                 PUSH    ES
  171.                 PUSH    CS
  172.                 POP     DS
  173.                 Assume  DS:CSEG         ;DS points to our code segment
  174.                 MOV     AX,3524H        ;Get DOS critical error vector
  175.                 CALL    DOS_FUNCTION    ;Do the DOS function
  176.                 PUSH    BX              ;Save old INT 24 vector on stack
  177.                 PUSH    ES
  178.  
  179. ; Replace the DOS severe error interrupt with our own routine.
  180.  
  181.                 MOV     DX,OFFSET NEWINT24
  182.                 MOV     AX,2524H        ;Setup to change INT 24h vector
  183.                 CALL    DOS_FUNCTION    ;DOS function to change vector
  184.  
  185. ; Try to open the file to determine if it already exists.  If it does,
  186. ; then just close it and increment the filename.
  187.  
  188. OPEN_FILE:      MOV     DX,OFFSET FILENAME ;DS:DX points to filename
  189.                 MOV     AX,3D00H        ;Open file for read access
  190.                 CALL    DOS_FUNCTION    ;Do the DOS function
  191.                 JC      OPEN_ERROR      ;If open error, take jump
  192.                 MOV     BX,AX           ;Need the handle in BX
  193.                 MOV     AH,3EH          ;Close this file
  194.                 CALL    DOS_FUNCTION    ;Do the DOS function
  195.                 CALL    INC_FILENAME    ;Try the next filename
  196.                 JMP     OPEN_FILE
  197. OPEN_ERROR:
  198.                 CMP     AX,2            ;Was it 'file not found' error?
  199.                 JNE     DOS_ERR_EXIT    ;Exit on any other error
  200.  
  201. ; Now create the file, then write buffer contents and close it.
  202.  
  203.                 MOV     DX,OFFSET FILENAME      ;DS:DX points to filename
  204.                 MOV     CX,0020H        ;Attribute for new file
  205.                 MOV     AH,3CH          ;Create file for writing
  206.                 CALL    DOS_FUNCTION    ;Do the DOS function
  207.                 JC      CLOSE_FILE      ;On any error, take jump
  208.  
  209.                 MOV     BX,AX           ;Save handle in BX
  210.  
  211.                 MOV     DX,OFFSET BUFFER;Point to output buffer
  212.                 MOV     CX,DS:CRT_SIZE  ;Write correct number of bytes
  213.                 MOV     AH,40H          ;DOS 'write to a device' function
  214.                 CALL    DOS_FUNCTION    ;Do the DOS function
  215. CLOSE_FILE:
  216.                 MOV     AH,3EH          ;DOS function to close the file
  217.                 CALL    DOS_FUNCTION    ;Do the DOS function
  218.                 CALL    INC_FILENAME    ;Move to next filename
  219.  
  220. DOS_ERR_EXIT:   POP     DS              ;Get INT 24H vector from stack
  221.                 Assume  DS:NOTHING
  222.                 POP     DX
  223.                 MOV     AX,2524H        ;Restore critical error vector
  224.                 CALL    DOS_FUNCTION    ;Do the DOS function
  225.  
  226.                 POP     ES              ;Finally restore all registers
  227.                 POP     DS
  228.                 POP     BP
  229.                 POP     DX
  230.                 POP     CX
  231.                 POP     BX
  232.                 POP     AX
  233.                 MOV     ACTIVE,0        ;CAPTURE is done now
  234.                 RET                     ;Finished writing to disk
  235.  
  236. WRITE_TO_FILE   ENDP
  237.  
  238. ;-----------------------------------------------------------------------
  239. ; This routine does a dos function by calling the old interrupt vector
  240. ;-----------------------------------------------------------------------
  241.                 Assume  DS:NOTHING, ES:NOTHING
  242. DOS_FUNCTION    PROC    NEAR
  243.  
  244.                 PUSHF                   ;These instructions simulate
  245.                 CLI                     ;an interrupt
  246.                 CALL    CS:OldInt21     ;Do the DOS function
  247.                 STI
  248.                 RET
  249.  
  250. DOS_FUNCTION    ENDP
  251.  
  252. ;-----------------------------------------------------------------------
  253. ; This procedure increments the number part of the filename.
  254. ;-----------------------------------------------------------------------
  255. INC_FILENAME    PROC    NEAR
  256.                 MOV     BX, FileNamePtr      ;Point to last digit
  257. INC_NEXT_CHAR:
  258.                 INC     BYTE PTR [BX]        ;Increment the extension
  259.                 CMP     BYTE PTR [BX],"9"    ;Check for carry
  260.                 JLE     INC_RETURN           ;If none, we're finished
  261.                 MOV     BYTE PTR [BX],"0"    ;Set this digit to zero
  262.                 DEC     BX                   ;Backup to next digit
  263.                 CMP     BX,OFFSET FILENAME+2 ;increment digits only
  264.                 JLE     INC_RETURN
  265.                 JMP     INC_NEXT_CHAR
  266. INC_RETURN:
  267.                 RET
  268. INC_FILENAME    ENDP
  269.  
  270. ;-----------------------------------------------------------------------
  271. ; Interrupt 09 (Keyboard)  Watch for trigger key.  When found, ignore
  272. ; it and execute the CAPTURE routine.
  273. ;-----------------------------------------------------------------------
  274. NEWINT09        PROC    FAR
  275.                 Assume  DS:NOTHING, ES:NOTHING
  276.  
  277.                 STI                     ;Allow other interrupts
  278.                 PUSH    AX              ;Must save processor state
  279.                 IN      AL,60H          ;Get the scan code
  280.                 CMP     AL,HOTKEY       ;Is it the hot key?
  281.                 JE      TRIGGER         ;If yes, check the mask
  282. INT09_EXIT:     POP     AX              ;Restore the processor state
  283.                 JMP     CS:OldInt09     ;Continue with ROM routine
  284. TRIGGER:
  285.                 PUSH    DS              ;Preserve DS register
  286.                 MOV     AX,BIOS_SEG     ;Get BIOS data segment
  287.                 MOV     DS,AX           ;Put it in a segment register
  288.                 Assume  DS:BIOS_SEG
  289.                 MOV     AL,KB_FLAG      ;Shift flags
  290.                 AND     AL,0FH          ; only
  291.                 CMP     AL,ShiftMask    ;Is the ALT key down?
  292.                 POP     DS              ;Restore DS register
  293.                 Assume  DS:NOTHING
  294.                 JNE     INT09_EXIT      ;If ALT not down, ignore it
  295.  
  296. ;Reset the keyboard and 8259 interrupt controller
  297.  
  298.                 IN      AL,61H
  299.                 MOV     AH,AL
  300.                 OR      AL,80H          ;Reset bit for keyboard
  301.                 OUT     61H,AL          ;Reset the keyboard
  302.                 MOV     AL,AH
  303.                 JMP     SHORT $+2       ;A short delay
  304.                 OUT     61H,AL          ;Reenable keyboard
  305.                 CLI
  306.                 MOV     AL,20H
  307.                 OUT     20H,AL          ;Reset interrupt controller
  308.                 STI
  309.  
  310.                 CMP     ACTIVE,0        ;Is CAPTURE already active?
  311.                 JNZ     SHORT_RET       ;If active, then exit
  312.                 MOV     ACTIVE,1        ;It's active now!
  313.  
  314.                 PUSH    BX              ;Must preserve all registers
  315.                 PUSH    CX
  316.                 PUSH    DX
  317.                 PUSH    BP
  318.                 PUSH    DI
  319.                 PUSH    DS
  320.                 PUSH    ES
  321.                 PUSH    CS
  322.                 POP     DS              ;Set DS to CSEG
  323.                 MOV     AX,BIOS_SEG     ;ES points to BIOS data area
  324.                 MOV     ES,AX
  325.                 Assume  DS:CSEG, ES:BIOS_SEG ;Assembler directives
  326.                 CALL    CAPTURE         ;Read the screen contents
  327.                 MOV     WriteFile,1     ;Indicate need to flush buffer
  328.                 POP     ES              ;Restore all registers
  329.                 POP     DS
  330.                 POP     DI
  331.                 POP     BP
  332.                 POP     DX
  333.                 POP     CX
  334.                 POP     BX
  335.                 Assume  DS:NOTHING, ES:NOTHING
  336.                 TEST    Busy_flags,011B ;Is DOS or BIOS disk busy?
  337.                 JNZ     SHORT_RET       ;If yes, then we must wait
  338.                 CALL    WRITE_TO_FILE   ;Otherwise, we'll do it now
  339. SHORT_RET:
  340.                 POP     AX              ;Stack must be restored
  341.                 IRET                    ;Now we're all done
  342.  
  343. NEWINT09        ENDP
  344.  
  345. ;-----------------------------------------------------------------------
  346. ; Interrupt 13H (BIOS diskette I/O) Set the busy flag during diskette I/O
  347. ;-----------------------------------------------------------------------
  348. NEWINT13        PROC    FAR
  349.                 Assume  DS:NOTHING, ES:NOTHING
  350.  
  351.                 PUSHF
  352.                 OR      CS:Busy_flags,010B      ;Set BIOS busy bit
  353.                 POPF
  354.                 PUSHF                           ;This simulates an interrupt
  355.                 CALL    CS:OldInt13             ;Do the BIOS function
  356.                 PUSHF                           ;Save result flags
  357.                 AND     Busy_flags,11111101B    ;Clear BIOS busy bit
  358.                 POPF                            ;Get back result flags
  359.                 STI                             ;Must return with interrupts on
  360.                 RET     2                       ;Return BIOS result flags
  361.  
  362. NEWINT13        ENDP
  363.  
  364. ;-----------------------------------------------------------------------
  365. ; Interrupt 16H (BIOS keyboard interface) Check to see if the buffer
  366. ; needs to be written.
  367. ;-----------------------------------------------------------------------
  368. NEWINT16        PROC    FAR
  369.                 Assume  DS:NOTHING, ES:NOTHING
  370.  
  371.                 Cmp     ax, ChkCode             ; is it 'are you there?' ?
  372.                 Jne     NI16A
  373. NI16AA:         XChg    ah, al                  ; if so, tell we are indeed!
  374.                 IRet
  375.  
  376. NI16A:          Cmp     ax, DumpCode            ; should we dump a screen?
  377.                 Jne     NI16B
  378.  
  379.                 PUSH    AX              ;Must preserve all registers
  380.                 PUSH    BX
  381.                 PUSH    CX
  382.                 PUSH    DX
  383.                 PUSH    BP
  384.                 PUSH    DI
  385.                 PUSH    DS
  386.                 PUSH    ES
  387.                 PUSH    CS
  388.                 POP     DS              ;Set DS to CSEG
  389.                 MOV     AX,BIOS_SEG     ;ES points to BIOS data area
  390.                 MOV     ES,AX
  391.                 Assume  DS:CSEG, ES:BIOS_SEG ;Assembler directives
  392.                 CALL    CAPTURE         ;Read the screen contents
  393.                 MOV     WriteFile,1     ;Indicate need to flush buffer
  394.                 POP     ES              ;Restore all registers
  395.                 POP     DS
  396.                 POP     DI
  397.                 POP     BP
  398.                 POP     DX
  399.                 POP     CX
  400.                 POP     BX
  401.                 POP     AX
  402.                 Assume  DS:NOTHING, ES:NOTHING
  403.                 TEST    Busy_flags,011B ;Is DOS or BIOS disk busy?
  404.                 JNZ     SHORT_RET       ;If yes, then we must wait
  405.                 CALL    WRITE_TO_FILE   ;Otherwise, we'll do it now
  406.                 Jmp Short NI16AA
  407.  
  408. NI16B:          Cmp     ax, RemoveCode          ; should we remove ourselves?
  409.                 Je      NI16Remove              ; if so, that's ok with us
  410.  
  411.                 CMP     CS:WriteFile,1          ;Anything to write to disk?
  412.                 JE      CHECK_DOS_Stat          ;If yes, see what DOS is doing
  413. BIOS_KB:
  414.                 JMP     CS:OldInt16             ;Just do normal KB routine
  415. CHECK_DOS_Stat:
  416.                 CMP     CS:DOS_Stat,0AH         ;Doing read string?
  417.                 JE      BEGIN_NOW               ;If yes, it's safe to begin
  418.                 CMP     CS:DOS_Stat,08H         ;Doing keyboard input?
  419.                 JNE     BIOS_KB                 ;If yes, it's safe to begin
  420. BEGIN_NOW:
  421.                 CALL    WRITE_TO_FILE           ;Write the buffer to disk
  422.                 OR      CS:Busy_flags,001B      ;Reset DOS busy bit
  423.                 JMP     CS:BIOS_KB              ;Continue with BIOS routine
  424.  
  425. NI16Remove:     Mov     dx, word ptr [cs:OldInt09]; otherwise start removal
  426.                 Mov     ax, word ptr [cs:OldInt09+2]
  427.                 Mov     ds, ax
  428.                 Mov     ax, SetVec+09h          ; Reestablish old INT 09h handler
  429.                 Int     DOSCall
  430.  
  431.                 Mov     dx, word ptr [cs:OldInt13]
  432.                 Mov     ax, word ptr [cs:OldInt13+2]
  433.                 Mov     ds, ax
  434.                 Mov     ax, SetVec+13h          ; Reestablish old INT 13h handler
  435.                 Int     DOSCall
  436.  
  437.                 Mov     dx, word ptr [cs:OldInt16]
  438.                 Mov     ax, word ptr [cs:OldInt16+2]
  439.                 Mov     ds, ax
  440.                 Mov     ax, SetVec+16h          ; Reestablish old INT 16h handler
  441.                 Int     DOSCall
  442.  
  443.                 Mov     dx, word ptr [cs:OldInt21]
  444.                 Mov     ax, word ptr [cs:OldInt21+2]
  445.                 Mov     ds, ax
  446.                 Mov     ax, SetVec+21h          ; Reestablish old INT 16h handler
  447.                 Int     DOSCall
  448.  
  449.                 Mov     ax, cs                  ; Return our segment
  450.                 IRet
  451.  
  452. NEWINT16        ENDP
  453.  
  454. ;-----------------------------------------------------------------------
  455. ; Interrupt 21H (DOS functions) Used to keep track of DOS function calls
  456. ;-----------------------------------------------------------------------
  457. NEWINT21        PROC    FAR
  458.                 Assume  DS:NOTHING, ES:NOTHING
  459.  
  460.                 PUSHF                           ;Save the flags
  461.                 MOV     CS:DOS_Stat,AH          ;Store the function number
  462.                 OR      CS:Busy_flags,001B      ;Set DOS busy bit
  463.  
  464.                 OR      AH,AH                   ;Doing function zero?
  465.                 JZ      JUMP_TO_DOS             ;If yes, take the jump
  466.                 CMP     AH, Exec                ;Doing EXEC function?
  467.                 JE      JUMP_TO_DOS             ;If yes, take the jump
  468.  
  469.                 POPF
  470.                 PUSHF
  471.                 CALL    CS:OldInt21             ;Do the DOS function
  472.  
  473.                 PUSHF                           ;Save the result flags
  474.  
  475.                 AND     CS:Busy_flags,11111110B ;Clear DOS busy bit
  476.                 CMP     CS:WriteFile,1          ;Anything to write to disk?
  477.                 JNE     NO_WRITE                ;If not, just return
  478.  
  479.                 CALL    WRITE_TO_FILE           ;Safe to access disk now
  480. NO_WRITE:
  481.                 POPF                    ;Recover DOS result flags
  482.                 STI                     ;Must return with interrupts on
  483.                 RET     2               ;Return with DOS result flags
  484. JUMP_TO_DOS:
  485.                 POPF
  486.                 JMP     CS:OldInt21
  487. NEWINT21        ENDP
  488.  
  489. ;-----------------------------------------------------------------------
  490. ; Interrupt 24H (critical DOS error).  This interrupt is only in
  491. ; effect during a write screen.  It is required to suppress the
  492. ; 'Abort, Retry, Ignore' message.  All fatal disk errors are ignored.
  493. ;-----------------------------------------------------------------------
  494. NEWINT24        PROC    FAR
  495.                 Assume  DS:NOTHING, ES:NOTHING
  496.                 XOR     AL,AL           ;Tells DOS to ignore the error
  497.                 IRET                    ;That's all we do here
  498.  
  499. NEWINT24        ENDP
  500.  
  501. ;----------------------------------------------------------------------
  502. ;  This area is overwritten by the dynamic buffers.
  503. ;----------------------------------------------------------------------
  504. PC              =       $
  505.  
  506. BUFFER          =       PC
  507. PC              =       PC+NBYTES
  508. LASTBYTE        =       PC
  509.  
  510. ;-----------------------------------------------------------------------
  511. ; Here is the code used to initialize HerCap. It is not kept resident.
  512. ; The buffer is located here and overlays the initialization code.
  513. ;-----------------------------------------------------------------------
  514.                 Assume  CS:CSEG, DS:CSEG, ES:NOTHING
  515.  
  516. INITIALIZE      PROC    NEAR
  517.  
  518.                 MOV     DX,OFFSET CopyRight
  519.                 MOV     AH, PrintString ;DOS display string service
  520.                 INT     DosCall         ;Display title message
  521.  
  522.                 Call    ParseArgs       ; check command line parameters
  523. ; ah has function code:
  524.                 Cmp     ah, 1           ; request for help?
  525.                 Jne     Init2           ; if not, proceed to check
  526.                 Mov     dx, Offset Usage; usage text
  527.                 Mov     al, 1           ; exit code
  528.  
  529. ShowMsg:        Push    ax
  530.                 Mov     ah, PrintString
  531.                 Int     DosCall
  532.                 Pop     ax
  533.                 mov     ah, ExitCode    ; exit with error code set earlier
  534.                 int     DosCall
  535.  
  536. ; Search for a previously installed copy of CAPTURE
  537.  
  538. Init2:          Cmp     ah, 3                   ; request for key help?
  539.                 Jne     Init2A
  540.                 Jmp     ShowKey                 ; if so, do it
  541. Init2A:         Mov     bx, ax
  542.                 Mov     ax, ChkCode             ; now check if we're loaded
  543.                 Int     16h                     ; already loaded <-> ax = 0
  544.  
  545.                 Cmp     bh, 2                   ; request for removal?
  546.                 Jne     Init2B
  547.                 Jmp     Remove                  ; proceed to remove
  548.                                                 ; now we should install;
  549. Init2B:         Cmp     ax, InstalledCode       ; are we there already?
  550.                 Jne     Init3                   ; if not, proceed normally
  551.  
  552.                 Mov     dx, Offset LoadedMsg    ; tell we're already there
  553.                 Mov     al, 2                   ; error code 2
  554.                 Jmp Short ShowMsg               ; and exit to DOS
  555.  
  556. Init3:          MOV     AX,GetVec+09h   ;Get keyboard break vector
  557.                 INT     DosCall
  558.                 MOV     WORD PTR [OldInt09],  BX  ;Save segment
  559.                 MOV     WORD PTR [OldInt09+2],ES  ;Save offset
  560.                 MOV     DX, OFFSET NEWINT09
  561.                 MOV     AX, SetVec+09h
  562.                 INT     DosCall         ;DOS function to change vector
  563.  
  564.                 MOV     AX,GetVec+13h   ;Get BIOS disk interrupt vector
  565.                 INT     DosCall
  566.                 MOV     WORD PTR [OldInt13],  BX  ;Save the segment
  567.                 MOV     WORD PTR [OldInt13+2],ES  ;Save the offset
  568.                 MOV     DX, OFFSET NEWINT13
  569.                 MOV     AX, SetVec+13h
  570.                 INT     DosCall         ;DOS function to change vector
  571.  
  572.                 MOV     AX,GetVec + 16h ;Get keyboard input vector
  573.                 INT     DosCall
  574.                 MOV     WORD PTR [OldInt16],  BX  ;Save the segment
  575.                 MOV     WORD PTR [OldInt16+2],ES  ;Save the offset
  576.                 MOV     DX, OFFSET NEWINT16
  577.                 MOV     AX, SetVec + 16h
  578.                 INT     DosCall         ;DOS function to change vector
  579.  
  580.                 MOV     AX,GetVec+DosCall;Get DOS function vector
  581.                 INT     DosCall
  582.                 MOV     WORD PTR [OldInt21],  BX
  583.                 MOV     WORD PTR [OldInt21+2],ES
  584.                 MOV     DX, OFFSET NEWINT21
  585.                 MOV     AX, SetVec+DosCall
  586.                 INT     DosCall                 ; DOS function to change vector
  587.  
  588.                 Mov     si, Offset BaseName     ; pointer to file name proper
  589.                 Mov     di, FileNamePtr         ; pointer into buffer
  590.                 Push    ds
  591.                 Pop     es
  592.                 Mov     cx, 12                  ; max 12 chars length
  593.                 Repne   Movsb                   ; copy them!
  594.                 Mov     ax, FileNamePtr         ; make FileNamePtr point to
  595.                 Add     ax, 7                   ; last digit in name
  596.                 Mov     FileNamePtr, ax
  597. ;----------------------------test ----------------------------------
  598.                 Int     09h
  599. ;----------------------------test ----------------------------------
  600.  
  601. ;-----------------------------------------------------------------------
  602. ; Deallocate our copy of the environment.
  603. ; Leave code and space for the buffer resident.
  604. ;-----------------------------------------------------------------------
  605.  
  606.                 MOV     AX,DS:[002CH]   ;Get segment of environment
  607.                 MOV     ES,AX           ;Put it into ES
  608.                 MOV     AH,FreeMem      ;Release allocated memory
  609.                 INT     DosCall
  610.                 Mov     dx, Offset InstallMsg; tell we have installed
  611.                 Mov     ah, PrintString
  612.                 Int     DosCall
  613.  
  614.                 MOV     DX,(OFFSET LASTBYTE - OFFSET CSEG + 15)SHR 4
  615.                 MOV     AX,Keep
  616.                 INT     DosCall
  617.  
  618. ; Code for removal of resident part:
  619. Remove:         Cmp     ax, InstalledCode       ; request for removal
  620.                 Je      Remove1                 ; if we're there, proceed;
  621.                 Mov     dx, Offset NotThereMsg  ; otherwise tell we're not there
  622.                 Mov     al, 3
  623.                 Jmp     ShowMsg
  624.  
  625. Remove1:        Push    ds
  626.                 Mov     ax, RemoveCode          ; prepare removal
  627.                 Int     16h                     ; call our routine
  628.                 Pop     ds                      ; retrieve data segment address
  629.                 Mov     es, ax                  ; memory of routine:
  630.                 Mov     ah, FreeMem             ; free it!
  631.                 Int     DOSCall
  632.                 Mov     dx, Offset RemovedMsg   ; report unloading
  633.                 Xor     al, al
  634.                 Jmp     ShowMsg
  635.  
  636. ; Code for display of hot key:
  637. ShowKey:        Mov     dx, Offset HitKeyMsg    ; Tell we're all set
  638.                 Mov     ah, PrintString
  639.                 Int     DosCall
  640.  
  641.                 MOV     AX,GetVec+09h           ; Get keyboard break vector
  642.                 INT     DosCall
  643.                 MOV     WORD PTR [OldInt09],  BX; Save segment
  644.                 MOV     WORD PTR [OldInt09+2],ES; Save offset
  645.                 MOV     DX, OFFSET DummyInt09   ; point to our wee interceptor
  646.                 MOV     AX, SetVec+09h
  647.                 INT     DosCall                 ; DOS function to change vector
  648.  
  649. GetHotKey:      Xor     ah, ah                  ; Get a proper key
  650.                 Int     16h
  651.  
  652.                 Mov     dx, word ptr [cs:OldInt09] ; point back to normal
  653.                 Mov     ax, word ptr [cs:OldInt09+2]
  654.                 Push    ds
  655.                 Mov     ds, ax
  656.                 Mov     ax, SetVec+09h          ; Reestablish old INT 09h handler
  657.                 Int     DOSCall
  658.                 Pop     ds
  659.  
  660.                 Mov     ah, HotKey              ; recover hot key code
  661.                 Mov     al, ShiftMask           ; ... and shift mask
  662.                 Call    ShowNum                 ; display that number
  663.                 Mov     ax, 4C00h               ; exit with error code 0
  664.                 Int     DosCall
  665.  
  666. INITIALIZE      ENDP
  667.  
  668. ShowNum         Proc    Near
  669. ; displays ax in hex format
  670.                 Push    ax
  671.                 Push    cx
  672.                 Push    dx
  673.                 Mov     cx, 4                   ; 4 hex digits
  674.  
  675. ShowNum1:       Push    ax                      ; push it
  676.                 Push    cx
  677.                 Mov     cl, 4
  678.                 ShR     ax, cl                  ; shift right one nibble
  679.                 Pop     cx
  680.                 Loop    ShowNum1
  681.                                                 ; now 4 nibbles are on stack
  682.                 Mov     cx, 4
  683. ShowNum2:       Pop     dx                      ; recall next nibble
  684.                 And     dl, 0Fh                 ; mask out other nibbles
  685.                 Cmp     dl, 9                   ; is it above 9?
  686.                 Jbe     ShowNum3
  687.                 Add     dl, 'A'-'0'-10          ; convert to letter A..F
  688. ShowNum3:       Add     dl, '0'                 ; convert to digit
  689.                 Mov     ah, PrintChar           ; display it
  690.                 Int     DosCall
  691.                 Loop    ShowNum2
  692.  
  693.                 Pop     dx
  694.                 Pop     cx
  695.                 Pop     ax
  696.                 Ret
  697. ShowNum         EndP
  698.  
  699. ParseArgs       Proc    Near
  700. ; parse command line arguments; return action code in ah:
  701. ; ah=0: install; ah=1: usage; ah=2: remove; ah=3: display hot key
  702. ; also sets path string and/or hot key code
  703.  
  704.                 Push    si
  705.                 Push    di
  706.                 Mov     si, Offset CmdLine + 1  ; point to command line
  707.                 Xor     ah, ah                  ; init cmd marker
  708.  
  709. PANext:         Lodsb                           ; get next char
  710.                 Cmp     al, CR                  ; at end?
  711.                 Je      PADone                  ; if so, finish
  712.                 Cmp     al, ' '                 ; ignore this?
  713.                 Je      PANext
  714.                 Cmp     al, ','                 ; ignore this?
  715.                 Je      PANext
  716.                 Cmp     al, Tab                 ; ignore this?
  717.                 Je      PANext
  718.                 Cmp     al, '/'                 ; switch char?
  719.                 Je      PASwitch                ; skip if so
  720.                 Cmp     al, '-'                 ; switch char?
  721.                 Jne     PAUsage                 ; skip if not
  722.  
  723. PASwitch:       Lodsb                           ; which switch?
  724.  
  725.                 Or      al, 20h                 ; convert to lower case
  726.                 Cmp     al, 'u'                 ; request uninstallation?
  727.                 Jne     PASw3                   ; skip if not
  728.                 Mov     ah, 2                   ; remember to remove
  729.                 Jmp Short PANext
  730.  
  731. PASw3:          Cmp     al, 'k'                 ; hot key spec?
  732.                 Jne     PASw4                   ; skip if not
  733.                 Mov     bh, ah
  734.                 Call    GetNum                  ; returns number in ax
  735.                 Or      ax, ax                  ; hot key help requested?
  736.                 Je      PASw3A                  ; if so, jot it down!
  737.                 Mov     HotKey, ah
  738.                 Mov     ShiftMask, al
  739.                 Mov     ah, bh
  740.                 Jmp Short PANext
  741. PASw3A:         Mov     ah, 3                   ; 'hot key help' request
  742.                 Jmp Short PANext
  743.  
  744. PASw4:          Cmp     al, 'p'                 ; request for outfile path?
  745.                 Je      PASw4A                  ; if so, proceed to store it
  746.  
  747. PAUsage:        Mov     ah, 1                   ; otherwise illegal arg
  748.  
  749. PADone:         Pop     di
  750.                 Pop     si
  751.                 Ret
  752.  
  753. ; get path, store it in appropriate buffer:
  754. PASw4A:         Mov     di, FileNamePtr         ; pointer to path buffer
  755.  
  756. PASw4B:         Lodsb                           ; get next byte
  757.                 Cmp     al, CR                  ; end of cmd line?
  758.                 Je      PASw4C
  759.                 Cmp     al, ' '                 ; end of arg?
  760.                 Je      PASw4C
  761.                 Cmp     al, Tab                 ; end of arg?
  762.                 Je      PASw4C
  763.                 Stosb                           ; else store char in path
  764.                 Jmp Short PASw4B
  765.  
  766. PASw4C:         Dec     si                      ; decrement cmd line ptr
  767.                 Cmp     byte ptr [di-1], '\'    ; does path end in '\'?
  768.                 Je      PASw4D
  769.                 Cmp     byte ptr [di-1], ':'    ; does path end in ':'?
  770.                 Je      PASw4D
  771.  
  772.                 Mov     al, '\'                 ; else force ending '\'
  773.                 Stosb
  774.  
  775. PASw4D:         Mov     FileNamePtr, di         ; update path pointer
  776.                 Jmp     PANext                  ; and scan on
  777.  
  778. ParseArgs       EndP
  779.  
  780. GetNum          Proc    Near
  781. ; reads hex number from current position in command line (ds:si),
  782. ; returns it in ax
  783.                 Push    bx
  784.                 Push    cx
  785.                 Xor     bx, bx                  ; assemble number here
  786.                 Mov     cl, 4                   ; convenient shift factor
  787.  
  788. GetNum1:        Lodsb                           ; get next char
  789.                 Cmp     al, CR                  ; check if end of argument
  790.                 Je      GetNumEnd
  791.                 Cmp     al, ' '                 ; ...
  792.                 Je      GetNumEnd
  793.                 Cmp     al, Tab                 ; ...
  794.                 Je      GetNumEnd
  795.                 Or      al, 20h                 ; make lowercase
  796.                 Sub     al, '0'                 ; try to make it a decimal digit
  797.                 Jc      GetNum1                 ; was too small; ignore
  798.                 Cmp     al, 9
  799.                 Jbe     GetNum2                 ; success!
  800.                 Sub     al, 'a'-'0'+10          ; else, try true hex digit
  801.                 Jc      GetNum1                 ; too small; ignore
  802.                 Cmp     al, 15
  803.                 Ja      GetNum1                 ; too large; ignore
  804.  
  805. GetNum2:        ShL     bx, cl                  ; shift earlier digits
  806.                 Or      bl, al                  ; add in new digit
  807.                 Jmp Short GetNum1
  808.  
  809. GetNumEnd:      Mov     ax, bx                  ; clean up
  810.                 Dec     si                      ; back up pointer
  811.                 Pop     cx
  812.                 Pop     bx
  813.                 Ret
  814.  
  815. GetNum          EndP
  816.  
  817. DummyInt09      PROC    FAR
  818. ; same as above, except we just get a key and store it away safely
  819.                 Assume  DS:NOTHING, ES:NOTHING
  820.  
  821.                 STI                     ;Allow other interrupts
  822.                 PUSH    AX              ;Must save processor state
  823.                 IN      AL,60H          ;Get the scan code
  824.                 Or      al, al
  825.                 Je      DummyI09Exit
  826.                 Mov     HotKey, al      ; store it as hot key
  827.                 PUSH    DS              ;Preserve DS register
  828.                 MOV     AX,BIOS_SEG     ;Get BIOS data segment
  829.                 MOV     DS,AX           ;Put it in a segment register
  830.                 Assume  DS:BIOS_SEG
  831.                 MOV     AL,KB_FLAG      ;Shift flags
  832.                 AND     AL,0FH          ; only
  833.                 Mov     ShiftMask, al   ;stow flags away
  834.                 POP     DS              ;Restore DS register
  835.  
  836. DummyI09Exit:   POP     AX              ;Restore the processor state
  837.                 JMP     CS:OldInt09     ;Continue with ROM routine
  838.  
  839. DummyInt09      EndP
  840.  
  841. BaseName        db      'SCN00000.TXT', 0       ; The first filename
  842.  
  843. Usage           db      CR, LF, CR, LF
  844.                 db      'TextCap 2.0 resident text screen capture', CR,LF,CR,LF
  845.                 db      'Usage: TextCap [args]    where args may be', CR, LF
  846.                 db      '/?         : this help screen', CR, LF
  847.                 db      '/K<number> : hex code of hot key; default is 4304 for '
  848.                 db      'Ctrl-F9', CR, LF
  849.                 db      '             (use /K? to find codes for keys!)', CR, LF
  850.                 db      '/P<path>   : for screen dumps; default is current '
  851.                 db      'directory', CR, LF
  852.                 db      '/U         : uninstall', CR, LF
  853.                 db      '             no arg installs with default values'
  854.                 db      CR, LF, '$'
  855.  
  856. LoadedMsg       DB      CR, LF, "had already been installed.$"
  857. InstallMsg      DB      CR, LF, "has been installed.$"
  858. RemovedMsg      DB      CR, LF, "has been uninstalled.$"
  859. NotThereMsg     DB      CR, LF, "had not been installed.$"
  860. HitKeyMsg       DB      CR, LF, "Hit the key to check: $"
  861.  
  862. CSEG            ENDS
  863.                 END     START
  864.